﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

//化学平衡
namespace ChemicalEquilibrium
{
    public class A
    {
        public A() { }
    }

    public class B
    {
        public B() { }
    }

    public class AB
    {
        public A A;
        public B B;
        public AB() { }
    }

    public class G
    {
        public G() { }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Program P = new Program();
            P.Start();
            while (true)
            {
                string input = Console.ReadLine();

                if (input.ToLower() == "e") break;
 
                switch (input.ToLower())
                {
                    case "a":
                        P.AddA();
                        break;
                    case "b":
                        P.AddB();
                        break;
                    case "c":
                        P.SubA();
                        break;
                    case "d":
                        P.SubB();
                        break;
                    default:
                        break;
                }

                Console.Clear();
            }

            P.Abort();
        }

        /*  PAs生成A
         *  A与R结合生成AR
         *  AR激活一定数量G
         *  PAi分解A
         *  从化学平衡的角度来分析:
         *      A + R = AR
         *  当一定量的A和一定量的R发生反应,生成一定量的AR
         *  生成的一定量的AR又会不断的分解成一定量的A和R
         *  当生成AR与分解AR的速度相等时就达到了化学平衡状态
         *  设c(A),c(R),c(AR)为三种物质的摩尔浓度
         *  当反应处于平衡状态时,平衡常数 K = c(AR)/[c(A)*c(R)]
         *  初始状态 c(R) = m, c(A) = c(AR) = 0;
         *  PAs生成 n mol/L 的A时
         *  c(A) = n, c(R) = m, c(AR) = 0;
         *  此时一定量的A和R生成AR,反应速率为V(+)
         *  反应生成的AR开始分解,反应速率为V(-)
         *  假设速度V是c(A)和c(R)的函数,假设为:
         *      V(+) = a * c(A) * c(R) / (c(A) + c(R)),   0 < a < 1
         *      V(-) = b * c(AR),               0 < b < 1
         *  当达到平衡时V(+) = V(-)
         *      a * c(A) * c(R) / (c(A) + c(R)) = b * c(AR)
         *  由于平衡时AR的浓度是A和R减少的浓度,则
         *      c(A) = m - c(AR)
         *      c(B) = n - c(AR)
         *  所以
         *      a * (m - c(AR)) * (n - c(AR)) / (m + n - 2 * c(AR)) = b * c(AR)
         *      
         */

        List<ThreadEventWait> TEWs = new List<ThreadEventWait>();

        Queue<A> As = new Queue<A>();
        Queue<A> AsRelease = new Queue<A>();
        Queue<B> Bs = new Queue<B>();
        Queue<AB> ABsCombined = new Queue<AB>();
        Queue<AB> ABsDetached = new Queue<AB>();

        public Program()
        {
            for (int i = 0; i < 1000; i++)
            {
                Bs.Enqueue(new B());
                ABsDetached.Enqueue(new AB());
            }

            for (int i = 0; i < 10000; i++)
            {
                AsRelease.Enqueue(new A());
                ABsDetached.Enqueue(new AB());
            }

            TEWs.Add(new ThreadEventWait(100, new OperateCallback(OperateAandBtoAB)));
            TEWs.Add(new ThreadEventWait(100, new OperateCallback(OperateABtoAandB)));
            TEWs.Add(new ThreadEventWait(100, new OperateCallback(OperateShowData)));
            TEWs.Add(new ThreadEventWait(100, new OperateCallback(OperateReleaseA)));
            TEWs.Add(new ThreadEventWait(1000, new OperateCallback(OperateCreateA)));
        }

        public void Start()
        {
            foreach (ThreadEventWait TEW in TEWs) TEW.Start();
        }

        public void Abort()
        {
            foreach (ThreadEventWait TEW in TEWs) TEW.Abort();
        }

        public void AddA()
        {
            for (int i = 0; i < 1000; i++)
            {
                if (AsRelease.Count == 0) break;

                As.Enqueue(AsRelease.Dequeue());
            }
        }

        public void AddB()
        {
            for (int i = 0; i < 1000; i++)
            {
                Bs.Enqueue(new B());
            }
        }

        public void SubA()
        {
            for (int i = 0; i < 1000; i++)
            {
                if (As.Count == 0) break;

                As.Enqueue(As.Dequeue());
            }
        }

        public void SubB()
        {
            for (int i = 0; i < 1000; i++)
            {
                if (Bs.Count == 0) break;

                Bs.Dequeue();
            }
        }

        public void OperateAandBtoAB()
        {
            int C = As.Count * Bs.Count / (As.Count + Bs.Count) / 10;

            for (int i = 0; i < C; i++)
            {
                if (this.As.Count == 0 || this.Bs.Count == 0
                    || this.ABsDetached.Count == 0) break;

                AB ab = this.ABsDetached.Dequeue();
                ab.A = this.As.Dequeue();
                ab.B = this.Bs.Dequeue();
                this.ABsCombined.Enqueue(ab);
            }
        }

        public void OperateABtoAandB()
        {
            int C = ABsCombined.Count / 10 + 1;

            for (int i = 0; i < C; i++)
            {
                if (this.ABsCombined.Count == 0) break;

                AB ab = this.ABsCombined.Dequeue();
                this.As.Enqueue(ab.A);
                this.Bs.Enqueue(ab.B);
                this.ABsDetached.Enqueue(ab);
            }

            //Console.Clear();
            //Console.WriteLine(string.Format("A : {0} \nB : {1} \nAB : {2}", this.As.Count, this.Bs.Count, this.ABsCombined.Count));
        }

        public void OperateShowData()
        {
            Console.Clear();
            Console.WriteLine(string.Format("A : {0} \nB : {1} \nAB : {2}", As.Count, Bs.Count, ABsCombined.Count));
        }
        Random R = new Random();
        public void OperateCreateA()
        {
            int count = R.Next(1000);

            for (int i = 0; i < count; i++)
            {
                if (AsRelease.Count == 0) break;

                As.Enqueue(AsRelease.Dequeue());
            }
        }

        public void OperateReleaseA()
        {
            for (int i = 0; i < 100; i++)
            {
                if (As.Count == 0) break;

                AsRelease.Enqueue(As.Dequeue());
            }
        }

    }

    public delegate void OperateCallback();

    public class ThreadEventWait
    {
        public static AutoResetEvent EventWait = new AutoResetEvent(true);

        Thread Thread;

        OperateCallback Operate;

        int Timeout;

        public ThreadEventWait(int timeout, OperateCallback operate)
        {
            this.Timeout = timeout;

            this.Operate = operate;

            this.Thread = new Thread(new ThreadStart(ThreadFunction));
        }

        public void Start()
        {
            Thread.Start();
        }

        public void Abort()
        {
            Thread.Abort();
        }

        Random R = new Random();

        public void ThreadFunction()
        {
            while (true)
            {
                if (EventWait.WaitOne())
                {
                    EventWait.Reset();

                    this.Operate();

                    EventWait.Set();
                }

                Thread.Sleep(this.Timeout);
                //Thread.Sleep(R.Next(1000));
            }
        }
    }
}
